using System;

namespace Core
{
    public partial class Entity
    {
        public Entity AddComponent(Type type)
        {
            var id = type.ToRuntimeId();
            if (components != null && components.TryGetValue(id, out var component))
            {
                return component;
            }
            component = Activator.CreateInstance(type) as Entity;
            component.InstanceId = id;
            Components[id] = component;
            component.Parent = this;
            return component;
        }

        public T AddComponent<T>() where T : Entity
        {
            var component = AddComponent(typeof(T)) as T;
            AwakeSystem.Awake(component);
            return component;
        }
        public T AddComponent<T, A>(A a) where T : Entity
        {
            var entity = AddComponent(typeof(T)) as T;
            AwakeSystem.Awake(entity, a);
            return entity;
        }
        public T AddComponent<T, A, B>(A a, B b) where T : Entity
        {
            var entity = AddComponent(typeof(T)) as T;
            AwakeSystem.Awake(entity, a, b);
            return entity;
        }
        public T AddComponent<T, A, B, C>(A a, B b, C c) where T : Entity
        {
            var entity = AddComponent(typeof(T)) as T;
            AwakeSystem.Awake(entity, a, b, c);
            return entity;
        }

        public void RemoveComponent<T>()where T : Entity
        {
            if (components == null)
                return;

            if (components.TryGetValue(typeof(T).ToRuntimeId(), out var component))
            {
                component.Dispose();
            }
        }

        public T AddChild<T>() where T : Entity
        {
            var entity = AddChild(typeof(T), IdGenerater.GenerateId());
            AwakeSystem.Awake(entity);
            return entity as T;
        }
        public T AddChild<T, A>(A a) where T : Entity
        {
            var entity = AddChild(typeof(T), IdGenerater.GenerateId());
            AwakeSystem.Awake(entity, a);
            return entity as T;
        }
        public T AddChild<T, A, B>(A a, B b) where T : Entity
        {
            var entity = AddChild(typeof(T), IdGenerater.GenerateId());
            AwakeSystem.Awake(entity, a, b);
            return entity as T;
        }
        public T AddChild<T, A, B, C>(A a, B b, C c) where T : Entity
        {
            var entity = AddChild(typeof(T), IdGenerater.GenerateId());
            AwakeSystem.Awake(entity, a, b, c);
            return entity as T;
        }

        public T AddChildWithId<T>(long id) where T : Entity
        {
            var entity = AddChild(typeof(T), id);
            AwakeSystem.Awake(entity);
            return entity as T;
        }

        public T AddChildWithId<T, A>(long id, A a) where T : Entity
        {
            var entity = AddChild(typeof(T), id);
            AwakeSystem.Awake(entity, a);
            return entity as T;
        }

        public T AddChildWithId<T, A, B>(long id, A a, B b) where T : Entity
        {
            var entity = AddChild(typeof(T), id);
            AwakeSystem.Awake(entity, a, b);
            return entity as T;
        }

        public T AddChildWithId<T, A, B, C>(long id, A a, B b, C c) where T : Entity
        {
            var entity = AddChild(typeof(T), id);
            AwakeSystem.Awake(entity, a, b, c);
            return entity as T;
        }

        private static Entity Create(Type type)
        {
            var entity = (Entity)Activator.CreateInstance(type);
            entity.InstanceId = 0;
            return entity;
        }

        private Entity AddChild(Type type, long id)
        {
            var entity = (Entity)Entity.Create(type);
            entity.InstanceId = id;
            entity.Parent = this;
            return entity;
        }
    }
}